package ddz.logic.game;

import ch.qos.logback.classic.Logger;
import com.kaka.notice.Message;
import com.kaka.notice.annotation.Handler;
import ddz.constants.Crypto;
import ddz.constants.ErrCode;
import ddz.constants.ErrLevel;
import ddz.constants.OpCode;
import ddz.core.*;
import ddz.db.dao.TableDao;
import ddz.db.dao.UserDao;
import ddz.db.entity.UserInfo;
import ddz.db.service.TableTokenService;
import ddz.net.LogicDataHandler;
import ddz.net.ProtocolMessage;
import ddz.numerical.manager.ConfTimeoutInfoManager;
import ddz.numerical.pojo.ConfTimeoutInfo;
import ddz.protos.Game;
import ddz.protos.GameRecovery;
import ddz.scheduler.QuartzFacade;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 数据恢复
 *
 * @author zkpursuit
 */
@Handler(cmd = OpCode.cmd_recovery, type = String.class)
public class RecoveryHandler extends LogicDataHandler {

    private final static Logger logger = (Logger) LoggerFactory.getLogger(RecoveryHandler.class);

    @Override
    public void execute(ProtocolMessage msg) throws Exception {
        UserInfo userInfo = (UserInfo) msg.getBody();
        long deskId = userInfo.getDeskId();
        TableDao tableDao = this.retrieveProxy(TableDao.class);
        Table table = tableDao.getDesk(deskId);
        if (table == null) {
            logger.error("玩家[{}]加入的房间 [{}] 无有效的可用数据", msg.uid(), deskId);
            sendError(msg.ctx(), opcode(), ErrLevel.ERROR, ErrCode.data_err);
            return;
        }

        int roomStateValue = table.getState().getValue();

        GameRecovery.ScRecovery.Builder scReconnBuilder = GameRecovery.ScRecovery.newBuilder();
        GameRecovery.Room.Builder roomBuilder = GameRecovery.Room.newBuilder();
        roomBuilder.setId(deskId)
                .setMode(table.getMode())
                .setPlace(table.getPlace())
                .setState(roomStateValue)
                .setDizhuSeat(table.getDizhuSeatIndex())
                .setLaizi(table.getLaiziPoint());

        UserDao userDao = this.retrieveProxy(UserDao.class);
        Player[] members = table.getPlayers();
        for (Player member : members) {
            if (member != null) {
                boolean isMingPai = table.isMingPai(member.getSeatIndex());
                UserInfo info = userDao.getUserInfo(member.getUid());
                Game.PlayerInfo.Builder playerInfoBuilder = Game.PlayerInfo.newBuilder();
                playerInfoBuilder.setBeans(info.getGold());
                playerInfoBuilder.setHeadImg(info.getHeadImg());
                playerInfoBuilder.setNickname(info.getNickname());
                playerInfoBuilder.setSex(info.getSex());
                playerInfoBuilder.setMingPai(isMingPai);
                playerInfoBuilder.setReady(member.isReady());
                playerInfoBuilder.setSeat(member.getSeatIndex());
                playerInfoBuilder.setUid(member.getUid());
                playerInfoBuilder.setTrustee(member.getTimeoutCount() >= 2);

                playerInfoBuilder.setUsedCounter(member.isUsedCounter());
                playerInfoBuilder.setPriorLookDiPai(member.isPriorLookDiPai());
                roomBuilder.addPlayers(playerInfoBuilder.build());

                if (member.getMycards() != null && member.getMycards().getCardCount() > 0) {
                    int[] cards = member.getMycards().getCards();
                    if (cards != null && cards.length > 0) {
                        Game.PlayerCards.Builder playerCardsBuilder = Game.PlayerCards.newBuilder();
                        playerCardsBuilder.setSeat(member.getSeatIndex());
                        Game.Cards.Builder cardsBuilder = Game.Cards.newBuilder();
                        for (int card : cards) {
                            if (member.getUid().equals(msg.uid()) || isMingPai) {
                                cardsBuilder.addCard(card);
                            } else {
                                cardsBuilder.addCard(0);
                            }
                        }
                        playerCardsBuilder.setCards(cardsBuilder.build());
                        roomBuilder.addPcardsList(playerCardsBuilder.build());
                    }
                }
            }
        }
        Player player = table.getPlayerByUid(msg.uid());
        int[] diCards = table.getDiCards();
        if (diCards != null) {
            if (player.isPriorLookDiPai() || table.getState().getValue() >= TableState.jia_bei.getValue()) {
                for (int card : diCards) {
                    roomBuilder.addDiPai(card);
                }
            }
        }
        int[] beis = table.getMultiple();
        roomBuilder.setBei(beis[player.getSeatIndex()]);
        List<OptRecord> records = this.getLastRoundRecords(table);
        if (records != null && !records.isEmpty()) {
            for (OptRecord record : records) {
                GameRecovery.Record.Builder recordBuilder = GameRecovery.Record.newBuilder()
                        .setSeatIndex(record.getSeatIndex())
                        .setTimestamp(record.getTimestamp())
                        .setType(record.getOptType().getId());
                if (record.getOptType() == OptType.chu) {
                    int[] cards = ((ChuRecord) record).getDiscardCards();
                    Game.Cards.Builder cardsBuilder = Game.Cards.newBuilder();
                    for (int card : cards) {
                        cardsBuilder.addCard(card);
                    }
                    recordBuilder.setCards(cardsBuilder.build());
                }
                roomBuilder.addRecords(recordBuilder.build());
            }
        }
        scReconnBuilder.setRoom(roomBuilder.build());
        this.sendData(msg.uid(), Crypto.isCrypto, opcode(), scReconnBuilder.build().toByteArray());
        //更新记牌器
        sendMessage(new Message(OpCode.cmd_counter, table));

        QuartzFacade quartzFacade = (QuartzFacade) getFacade();
        if (!quartzFacade.isExistScheduleJob(OpCode.timer_auto_play, "desk:" + table.getId())) {
            this.sendMessage(new Message(OpCode.cmd_show_opts, table));
        } else {
            TableTokenService optTokenService = this.retrieveProxy(TableTokenService.class);
            ConfTimeoutInfoManager confTimeoutInfoManager = this.retrieveProxy(ConfTimeoutInfoManager.class);
            ConfTimeoutInfo diZhuTimeoutInfo = confTimeoutInfoManager.getDiZhuInfo();
            ConfTimeoutInfo chuOrPassTimeoutInfo = confTimeoutInfoManager.getChuOrPassInfo();
            ShowOptsHandler showOptsHandler = new ShowOptsHandler();
            if (table.getState() == TableState.jia_bei) {
                ConfTimeoutInfo jiaBeiTimeoutInfo = confTimeoutInfoManager.getJiaBeiInfo();
                String token = optTokenService.createToken(table.getId(), table.getStep(), player.getSeatIndex());
                showOptsHandler.buildJiaBeiData(player, userInfo, token, jiaBeiTimeoutInfo);
            } else if (table.getState() == TableState.qiang_dizhu || table.getState() == TableState.playing) {
                int nextOperateSeatIdx = table.getWaitOperateSeatIndex(); //下一个操作方
                if (nextOperateSeatIdx == player.getSeatIndex()) {
                    if (table.getState() == TableState.qiang_dizhu) {
                        if (!table.isPassDiZhu(nextOperateSeatIdx)) {
                            String token = optTokenService.createToken(table.getId(), table.getStep(), nextOperateSeatIdx);
                            byte[] optRespBytes = showOptsHandler.buildDizhuDataForSelf(table, player, token, diZhuTimeoutInfo);
                            this.sendData(msg.uid(), Crypto.isCrypto, Integer.parseInt(OpCode.cmd_show_opts), optRespBytes);
                        }
                    } else if (table.getState() == TableState.playing) {
                        String token = optTokenService.createToken(table.getId(), table.getStep(), nextOperateSeatIdx);
                        byte[] optRespBytes = showOptsHandler.buildPlayingDataForSelf(table, player, token, chuOrPassTimeoutInfo);
                        this.sendData(msg.uid(), Crypto.isCrypto, Integer.parseInt(OpCode.cmd_show_opts), optRespBytes);
                    }
                } else {
                    if (table.getState() == TableState.qiang_dizhu) {
                        byte[] optRespBytes = showOptsHandler.buildDizhuDataForOther(player, diZhuTimeoutInfo);
                        this.sendData(msg.uid(), Crypto.isCrypto, Integer.parseInt(OpCode.cmd_show_opts), optRespBytes);
                    } else if (table.getState() == TableState.playing) {
                        byte[] optRespBytes = showOptsHandler.buildPlayingDataForOther(player, chuOrPassTimeoutInfo);
                        this.sendData(msg.uid(), Crypto.isCrypto, Integer.parseInt(OpCode.cmd_show_opts), optRespBytes);
                    }
                }
            }
        }
        Map<String, Object> paramMap = new HashMap<>(5);
        paramMap.put("mode", table.getMode());
        paramMap.put("place", table.getPlace());
        paramMap.put("userInfo", userInfo);
        this.sendMessage(new ProtocolMessage(Integer.parseInt(OpCode.cmd_select_place), paramMap, msg.uid()));
    }

    /**
     * 获取最后一回合的操作记录列表
     *
     * @param table
     * @return
     */
    List<OptRecord> getLastRoundRecords(Table table) {
        List<OptRecord> records = table.getRecords();
        if (records == null || records.isEmpty()) return null;
        List<OptRecord> list = new ArrayList<>();
        if (table.getState() == TableState.jia_bei) {
            for (OptRecord record : records) {
                if (record.getOptType() == OptType.jiabei1
                        || record.getOptType() == OptType.jiabei2
                        || record.getOptType() == OptType.jiabei3) {
                    list.add(record);
                }
            }
        } else if (table.getState() == TableState.qiang_dizhu) {
            for (OptRecord record : records) {
                if (record.getOptType() == OptType.jiaodizhu
                        || record.getOptType() == OptType.bujiaodizhu
                        || record.getOptType() == OptType.qiangdizhu
                        || record.getOptType() == OptType.buqiangdizhu) {
                    list.add(record);
                }
            }
        } else if (table.getState() == TableState.playing) {
            int lastIdx = records.size() - 1;
            int startIdx = 0;
            for (int i = 0; i <= lastIdx; i++) {
                OptRecord record = records.get(i);
                if (record.getOptType() == OptType.chu) {
                    startIdx = i;
                    break;
                }
            }
            int passCount = 0;
            for (int i = lastIdx; i >= startIdx; i--) {
                OptRecord record = records.get(i);
                if (record.getOptType() == OptType.pass) {
                    passCount++;
                    if (passCount == table.getMaxPlayers() - 1) {
                        //连续两个pass表示为上一轮的结束，下一轮的开始即为两个连续pass之后
                        startIdx = i + passCount;
                        break;
                    }
                } else {
                    passCount = 0;
                }
            }
            for (int i = startIdx; i <= lastIdx; i++) {
                OptRecord record = records.get(i);
                list.add(record);
            }
        }
        return list;
    }

}
